home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / snws190s.zip / ARTICLE.C < prev    next >
C/C++ Source or Header  |  1992-06-21  |  23KB  |  869 lines

  1. /*
  2.  
  3.     SNEWS 1.90
  4.  
  5.     news - routines to read and display an article
  6.  
  7.  
  8.     Copyright (C) 1991  John McCombs, Christchurch, NEW ZEALAND
  9.                         john@ahuriri.gen.nz
  10.                         PO Box 2708, Christchurch, NEW ZEALAND
  11.  
  12.     This program is free software; you can redistribute it and/or modify
  13.     it under the terms of the GNU General Public License, version 1, as
  14.     published by the Free Software Foundation.
  15.  
  16.     This program is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.  
  21.     See the file COPYING, which contains a copy of the GNU General
  22.     Public License.
  23.  
  24.  */
  25.  
  26.  
  27. #include "defs.h"
  28. #include "snews.h"
  29. #include <alloc.h>
  30.  
  31. #include <io.h>
  32. #include <ctype.h>
  33.  
  34. int xfile2 = FALSE;
  35.  
  36. void ReplyAddress(TEXT *tx, char *subject);
  37.  
  38. /*------------------------- read in an article -----------------------------*/
  39. TEXT *load_article(char *fnx, long offset)
  40. {
  41.     /*
  42.      *  Open the file and read it.  Save the author and organisation
  43.      *  fill in the structures
  44.      */
  45.  
  46.     FILE *tmp_file;
  47.     char buf[256], lnbuf[256], *p, *s;
  48.     TEXT *tx;
  49.     LINE *ln, *lz;
  50.     int  ct, i;
  51.  
  52.     tx = NULL;
  53.     ct = 0;
  54.  
  55.     if ((tmp_file = fopen(fnx, "rb")) != NULL) {
  56.  
  57.         fseek(tmp_file, offset, SEEK_SET);
  58.  
  59.         tx = xmalloc(sizeof(TEXT));
  60.         tx->top = NULL;
  61.         tx->start = NULL;
  62.         strcpy(tx->follow_up, "");
  63.         strcpy(tx->author, " ** none ** ");
  64.         strcpy(tx->organisation, " ** none ** ");
  65.  
  66.         while (fgets(buf, 255, tmp_file) != NULL) {
  67.  
  68.             if (strncmp(buf, "@@@@END", 7) == 0) break;
  69.  
  70.             expand_tabs(buf, 255);
  71.  
  72.             /*
  73.              *  We now have a line of input.  If the line is two long
  74.              *  it is wrapped at spaces or '!'.  The lines of text are
  75.              *  stored in LINE structures
  76.              */
  77.             p = &buf[0];
  78.             while (strlen(p) > 0) {
  79.  
  80.                 strcpy(lnbuf, p);
  81.                 if (strlen(p) <= 80) {
  82.                     strcpy(lnbuf, p);
  83.                     *p = '\x00';
  84.                 } else {
  85.                     p += 79;
  86.                     for (i = 79; i > 50; i--) {
  87.                         if ((lnbuf[i] == ' ') || (lnbuf[i] == '!'))
  88.                             break;
  89.                         p--;
  90.                     }
  91.                     lnbuf[i] = '\x00';
  92.                 }
  93.  
  94.                 /* is it the first line - if so int the TEXT structure */
  95.                 if (ct == 0) {
  96.                     ln = xmalloc(sizeof(LINE));
  97.                     ln->last = NULL;
  98.                     tx->top = ln;
  99.                 } else {
  100.                     lz = ln;
  101.                     ln->next = xmalloc(sizeof(LINE));
  102.                     ln = ln->next;
  103.                     ln->last = lz;
  104.                 }
  105.  
  106.                 lnbuf[79] = '\x00';
  107.                 ln->index = ct;
  108.                 strcpy(ln->data, lnbuf);
  109.  
  110.                 if ((strlen(lnbuf) == 1) && (tx->start == NULL))
  111.                     tx->start = ln;
  112.  
  113.                 ct++;
  114.  
  115.                 /* save the header info */
  116.                 if ((tx->start == NULL) && (strncmp("From:", lnbuf, 5) == 0)) {
  117.                     s = lnbuf + 5;
  118.                     while (*s && isspace(*s)) s++;
  119.                     *(s + WHO_LENGTH - 1) = '\0';
  120.                     strcpy(tx->author, s);
  121.                 }
  122.                 if ((tx->start == NULL) &&  ((strncmp("Organisation:", lnbuf, 13) == 0) || (strncmp("Organization:", lnbuf, 13) == 0))) {
  123.                     s = lnbuf + 13;
  124.                     while (*s && isspace(*s)) s++;
  125.                     *(s + ORG_LENGTH - 1) = '\0';
  126.                     strcpy(tx->organisation, s);
  127.                 }
  128.  
  129.                 if ((tx->start == NULL) && (strncmp("Followup-To:", lnbuf, 12) == 0)) {
  130.                     s = lnbuf + 12;
  131.                     while (*s && isspace(*s)) s++;
  132.                     *(s + 80 - 1) = '\0';
  133.                     strcpy(tx->follow_up, s);
  134.                 }
  135.             }
  136.  
  137.         }
  138.  
  139.         ln->next = NULL;
  140.         tx->lines = ct;
  141.  
  142.         fclose(tmp_file);
  143.     }
  144.  
  145.     return(tx);
  146. }
  147.  
  148.  
  149.  
  150. /*---------------------- deallocate article memory ------------------------*/
  151. void free_article(TEXT *t)
  152. {
  153.  
  154.     LINE *l, *k;
  155.  
  156.     l = t->top;
  157.     while (l != NULL) {
  158.         k = l;
  159.         l = l->next;
  160.         free(k);
  161.     }
  162.  
  163.     free(t);
  164. }
  165.  
  166.  
  167.  
  168. /*---------------------------- read an article ----------------------------*/
  169. int read_article(ACTIVE *gp, TEXT *tx, char *subject, int a_ct, int of_ct)
  170. {
  171.     /*
  172.      *  This routine alloas the user to read an article
  173.      */
  174.  
  175.     LINE   *this, *tmp;   /* current thread                    */
  176.     int    exit_code;     /* why we are exiting the loop      */
  177.     char   sub_tmp[80];
  178.  
  179.     int    ch, i;
  180.  
  181.     this = tx->start;
  182.     exit_code = 0;
  183.     show_article(gp, tx, subject, this, a_ct, of_ct);
  184.  
  185.     while ((exit_code == 0) || (exit_code == EX_DUMMY)) {
  186.  
  187.     exit_code = 0;
  188.     gotoxy(1,25);
  189.         ch = getch();
  190.         switch (ch) {
  191.  
  192.             case 0      :
  193.                 ch = getch();
  194.  
  195.                 switch (ch) {
  196.  
  197.             case Fn1    :
  198.             show_help(HELP_ARTICLES);
  199.             break;
  200.  
  201.             case Fn2    :
  202.             show_values();
  203.             break;
  204.  
  205.                     case UP_ARR :
  206.                         if (this->last != NULL) {
  207.                             this = this->last;
  208.                             gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  209.                             delline();
  210.                             gotoxy(1,TEXT_LINE);
  211.                             insline();
  212.                             clreol();
  213.                             cputs(this->data);
  214.                         }
  215.                         exit_code = EX_DUMMY;
  216.                         break;
  217.  
  218.                     case DN_ARR :
  219.                         if (this->next != NULL) {
  220.                             this = this->next;
  221.                             gotoxy(1,TEXT_LINE);
  222.                             delline();
  223.                             gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
  224.                             insline();
  225.  
  226.                             tmp = this;
  227.                             for (i = 0; i < PAGE_LENGTH-1; i++) {
  228.                 if (tmp == NULL) break;
  229.                                 tmp = tmp->next;
  230.                             }
  231.  
  232.                 clreol();
  233.                 if (tmp == NULL) {
  234.                    cputs(" ");
  235.                 } else {
  236.                    cputs(tmp->data);
  237.                 }
  238.                         }
  239.                         exit_code = EX_DUMMY;
  240.                         break;
  241.  
  242.                     case PGUP   :
  243.             for (i = 0; i < PAGE_LENGTH-1; i++) {
  244.                             if (this->last == NULL) break;
  245.                             this = this->last;
  246.                         }
  247.                         break;
  248.  
  249.                     case PGDN   :
  250.             for (i = 0; i < PAGE_LENGTH-1; i++) {
  251.                             if (this->next == NULL) break;
  252.                             this = this->next;
  253.                         }
  254.                         break;
  255.  
  256.                     case HOME   :
  257.                         this = tx->start;
  258.                         break;
  259.  
  260.                     case END    :
  261.                         this = tx->start;
  262.                         while (this->next != NULL)
  263.                             this = this->next;
  264.                         break;
  265.  
  266.                     case LEFT    :
  267.                         exit_code = LEFT;
  268.                         break;
  269.  
  270.                     case RIGHT    :
  271.                         exit_code = RIGHT;
  272.                         break;
  273.  
  274.                     default     :
  275.                         exit_code = EX_DUMMY;
  276.                         break;
  277.                 }
  278.                 break;
  279.  
  280.             case 'p'    :
  281.                 strcpy(sub_tmp, "");
  282.                 post(NULL, gp->group, sub_tmp);
  283.                 break;
  284.  
  285.             case 'f'    :
  286.                 if (strcmp(tx->follow_up, "") == 0)
  287.                     post(tx, gp->group, subject);
  288.                 else
  289.                     post(tx, tx->follow_up, subject);
  290.                 break;
  291.  
  292.             case 'r'    :
  293.                 reply_to_article(tx, subject);
  294.                 break;
  295.  
  296.             case 'R'    :
  297.                 ReplyAddress(tx, subject);
  298.                 break;
  299.  
  300.             case 'm'    :
  301.                 mail_to_someone(tx);
  302.                 break;
  303.  
  304.             case 's'    :
  305.                 save_to_disk(tx);
  306.                 message("-- Done --");
  307.                 break;
  308.  
  309.         case 'w'    :
  310.         xfile2 = TRUE;
  311.         save_to_disk(tx);
  312.         xfile2 = FALSE;
  313.         message("--Done --");
  314.         break;
  315.  
  316.             case 'x'    :
  317.                 rot13(tx);
  318.                 break;
  319.  
  320.             case '?'    :
  321.             case 'h'    :
  322.                 show_help(HELP_ARTICLES);
  323.                 break;
  324.  
  325.             case TAB    :
  326.                 exit_code = EX_NEXT_UNREAD;
  327.                 break;
  328.  
  329.             case ENTER  :
  330.                 exit_code = EX_NEXT;
  331.                 break;
  332.  
  333.             case ESCAPE :
  334.                 exit_code = EX_QUIT;
  335.                 break;
  336.  
  337.             default     :
  338.                 exit_code = EX_DUMMY;
  339.                 break;
  340.         }                           /* note, there was a ';' here */
  341.         if (exit_code == 0)
  342.             show_article(gp, tx, subject, this, a_ct, of_ct);
  343.     }
  344.  
  345.     return(exit_code);
  346. }
  347.  
  348.  
  349.  
  350. /*-------------------- show the list of active groups -----------------------*/
  351. void show_article(ACTIVE *gp, TEXT *tx, char *subject, LINE *this, int a_ct,
  352.                   int of_ct)
  353. {
  354.     /*
  355.      *  This routine show a page of an article
  356.      */
  357.  
  358.     int    i;
  359.     char   buf[60];
  360.  
  361.  
  362.  
  363.     clrscr();
  364.     strcpy(buf, subject);
  365.     buf[49] = '\x00';
  366.  
  367.  
  368.     textbackground(headb);    textcolor(headf);
  369.     clreol();
  370.     cprintf("Group: %-30s                         Article: %2d of %2d\r\n",
  371.            gp->group, a_ct, of_ct);
  372.     clreol();
  373.     cprintf("Subject: %-50s          %4d lines\r\n", buf, tx->lines);
  374.     clreol();
  375. /*    cprintf("From: %s; %s", tx->author, tx->organisation);*/
  376.     cprintf("From: %s", tx->author);
  377.     textbackground(textb);    textcolor(textf);
  378.  
  379.  
  380.     gotoxy(1, TEXT_LINE);
  381.     for (i = 0; i < PAGE_LENGTH; i++) {
  382.         gotoxy(1, i+TEXT_LINE);
  383.         cputs(this->data);
  384.         this = this->next;
  385.         if (this == NULL) break;
  386.     }
  387.  
  388.     command("ESC=select thread   TAB=next unread   ENTER=next   F1 or '?'=help");
  389. }
  390.  
  391.  
  392.  
  393.  
  394.  
  395. /*-------------------------- save article --------------------------------*/
  396. void save_to_disk(TEXT *tx)
  397. {
  398.     /*
  399.      *  This routine saves an article to disk, appending if necessary
  400.      */
  401.  
  402.     FILE *tmp = NULL;
  403.     LINE *ln;
  404.     char fn[80];
  405.     int  ch;
  406.  
  407.     if (xfile2 == TRUE) {
  408.     strcpy(fn,"\\extract.nws");
  409.     } else {
  410.     message("Enter filename? ");
  411.     gets(fn);
  412.     }
  413.  
  414.     if (access(fn, 0) == 0) {
  415.     if (xfile2 == TRUE) {
  416.           if ((tmp = fopen(fn, "at")) == NULL) {
  417.          message("*** Cannot open file for appending - "
  418.              "press any key to continue ***");
  419.          getch();
  420.           }
  421.     } else {
  422.        message("File exists - append(y/n)? ");
  423.        while (((ch = getch()) != 'y') && (ch != 'n'));
  424.        if (ch == 'y') {
  425.           if ((tmp = fopen(fn, "at")) == NULL) {
  426.          message("*** Cannot open file for appending - "
  427.              "press any key to continue ***");
  428.          getch();
  429.           }
  430.        }
  431.  
  432.     }
  433.  
  434.     } else {
  435.  
  436.         if ((tmp = fopen(fn, "wt")) == NULL) {
  437.             message("*** Cannot open file for output - press a key to continue ***");
  438.             getch();
  439.         }
  440.  
  441.     }
  442.  
  443.     if (tmp != NULL) {
  444.     if (xfile2 == TRUE) {
  445.             fputs("\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
  446.                   "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\n",tmp);
  447.     }
  448.  
  449.         ln = tx->top;
  450.         while (ln != NULL) {
  451.             fputs(ln->data, tmp);
  452.         ln = ln->next;
  453.         }
  454.         fclose(tmp);
  455.     }
  456.  
  457. }
  458.  
  459.  
  460.  
  461.  
  462. /*-------------------------- reply to article ---------------------------*/
  463. void reply_to_article(TEXT *tx, char *subject)
  464. {
  465.     /*
  466.      *  Mail reply to article
  467.      */
  468.  
  469. #ifdef INCLUDE_SIG
  470.     FILE *sig;
  471.     char sig_fn[80];
  472. #endif
  473.  
  474.     FILE *tmp;
  475.     LINE *ln;
  476.     int  ch;
  477.     char fn[80];
  478.     char buf[256];
  479.     char author[80], msg_id[80];
  480.  
  481.     strcpy(fn, "reply.tmp");
  482.  
  483.     if ((tmp= fopen(fn, "wt")) != NULL) {
  484.  
  485.         strcpy(author, " ");
  486.         get_his_stuff(tx, author, msg_id);
  487.  
  488.         /* add the quoted message */
  489.         message("Quote article (y/n)? ");
  490.         while (((ch = getch()) != 'y') && (ch != 'n'));
  491.  
  492.         if (ch == 'y') {
  493.             fprintf(tmp, "\nIn article %s you write:\n\n", msg_id);
  494.             ln = tx->start;
  495.             while (ln != NULL) {
  496.                 fprintf(tmp, " > %s", ln->data);
  497.                 ln = ln->next;
  498.             }
  499.         }
  500.  
  501. #ifdef INCLUDE_SIG
  502.         /* append the signature if there is one */
  503.         strcpy(sig_fn, my_stuff.home);
  504.         strcat(sig_fn, my_stuff.signature);
  505.         if ((sig= fopen(sig_fn, "rt")) != NULL) {
  506.             fprintf(tmp, "\n--\n");
  507.             while (fgets(buf, 79, sig) != NULL)
  508.                 fputs(buf, tmp);
  509.         }
  510.  
  511.         fclose(sig);
  512. #endif
  513.         fclose(tmp);
  514.  
  515.         ch = 'e';
  516.  
  517. /* NEW BIT      includes send/abort/edit */
  518.         while ((ch != 's') && (ch != 'a')) {
  519.             if (ch == 'e') {
  520.                sprintf(buf, my_stuff.editor, fn);
  521.                system(buf);
  522.         }
  523.         clrscr();
  524.         gotoxy(1,23);
  525.             cprintf("  Mail reply addressed to: %s",author);
  526.         sprintf(buf,"Mail reply:   (S)end, (A)bort, or (E)dit again? (S/A/E):");
  527.             message(buf);
  528.         while (((ch = getch()) != 's') && (ch != 'a') && (ch != 'e'));
  529.             gotoxy(1,24);
  530.     }
  531.  
  532.        if (ch == 's') {
  533.             sprintf(buf, "mail -s \"Re: %s\" %s <%s", subject, author, fn);
  534.             system(buf);
  535.         }
  536.         unlink(fn);
  537.         message("-- Press any key to continue --");
  538.         getch();
  539.  
  540.     } else {
  541.         message("*** Cannot open temp file - press any key to continue ***");
  542.         getch();
  543.     }
  544.  
  545. }
  546.  
  547.  
  548.  
  549. /* ---------- (R)eply allowing specified address or alias ---------------- */
  550.  
  551. void ReplyAddress(TEXT *tx, char *subject)
  552. {
  553. #ifdef INCLUDE_SIG
  554.     FILE *sig;
  555.     char sig_fn[80];
  556. #endif
  557.  
  558.     FILE *tmp;
  559.     FILE *alias;
  560.     LINE *ln;
  561.     int  ch;
  562.     char *s;
  563.     char fn[80];
  564.     char buf[256];
  565.     char author[80], msg_id[80];
  566.  
  567.     strcpy(fn, "reply.tmp");
  568.  
  569.     if ((tmp= fopen(fn, "wt")) != NULL) {
  570.  
  571.         get_his_stuff(tx, author, msg_id);
  572.  
  573.         /* add the quoted message */
  574.         message("Quote article (y/n)? ");
  575.         while (((ch = getch()) != 'y') && (ch != 'n'));
  576.  
  577.         if (ch == 'y') {
  578.             fprintf(tmp, "\nIn article %s you write:\n\n", msg_id);
  579.             ln = tx->start;
  580.             while (ln != NULL) {
  581.                 fprintf(tmp, " > %s", ln->data);
  582.                 ln = ln->next;
  583.             }
  584.         }
  585.  
  586. #ifdef INCLUDE_SIG
  587.         /* append the signature if there is one */
  588.         strcpy(sig_fn, my_stuff.home);
  589.         strcat(sig_fn, my_stuff.signature);
  590.         if ((sig= fopen(sig_fn, "rt")) != NULL) {
  591.             fprintf(tmp, "\n--\n");
  592.             while (fgets(buf, 79, sig) != NULL)
  593.                 fputs(buf, tmp);
  594.         }
  595.  
  596.         fclose(sig);
  597. #endif
  598.         fclose(tmp);
  599.  
  600.     sprintf(buf, "Send reply to who (aliases allowed): ");
  601.         message(buf);
  602.         gets(author);
  603.  
  604.         if ((alias = fopen(my_stuff.alias_file,"rt")) != NULL) {
  605.             while (fgets(buf, 255, alias)!=NULL) {
  606.                 if (buf[0] == ';' || isspace(buf[0]))
  607.                     continue;
  608.                 if (strnicmp(author,buf,strlen(author)) == 0) {
  609.                     s = strchr(buf,' ');
  610.                     while (*s && isspace(*s)) s++;
  611.                     s = strtok(s, " ;\t\r\n");
  612.                     strcpy(author,s);
  613.                     break;
  614.                 }
  615.             }
  616.             fclose(alias);
  617.         }
  618.     ch = 'e';
  619.     while ((ch != 's') && (ch != 'a')) {
  620.             if (ch == 'e') {
  621.                sprintf(buf, my_stuff.editor, fn);
  622.                system(buf);
  623.             }
  624.             sprintf(buf,"Mail article:   (S)end, (A)bort, or (E)dit again? (S/A/E):");
  625.             message(buf);
  626.         while (((ch = getch()) != 's') && (ch != 'a') && (ch != 'e'));
  627.             gotoxy(1,24);
  628.     }
  629.     if (ch == 's') {
  630.         sprintf(buf, "mail -s \"%s\" %s <%s", subject, author, fn);
  631.             system(buf);
  632.         }
  633.         unlink(fn);
  634.         message("-- Press any key to continue --");
  635.         getch();
  636.  
  637.     } else {
  638.         message("*** Cannot open temp file - press any key to continue ***");
  639.         getch();
  640.     }
  641.  
  642. }
  643.  
  644.  
  645.  
  646.  
  647. /*-------------------------- reply to article ---------------------------*/
  648. void mail_to_someone(TEXT *tx)
  649. {
  650.     /*
  651.      *  Mail this article to someone
  652.      */
  653.  
  654.  
  655.     FILE *tmp;
  656.     LINE *ln;
  657.     int  ch;
  658.     char fn[80];
  659.     char buf[256], who[80];
  660.     char author[80], msg_id[80];
  661.  
  662.     strcpy(fn, "reply.tmp");
  663.  
  664.     if ((tmp= fopen(fn, "wt")) != NULL) {
  665.  
  666.         get_his_stuff(tx, author, msg_id);
  667.  
  668.         /* add the quoted message */
  669.         command("");
  670.         lmessage("Who do you want to mail this article to? ");
  671.         gets(who);
  672.  
  673.         fprintf(tmp, "\nThis article was forwarded to you by %s@%s (%s):\n\n",
  674.             my_stuff.user, my_stuff.my_domain, my_stuff.my_name);
  675.         fprintf(tmp,"--------------------------------- cut here -----------------------------\n\n");
  676.         ln = tx->top;
  677.         while (ln != NULL) {
  678.             fprintf(tmp, "%s", ln->data);
  679.             ln = ln->next;
  680.         }
  681.  
  682.         fprintf(tmp,"--------------------------------- cut here -----------------------------\n\n");
  683.  
  684.         fclose(tmp);
  685.  
  686.         sprintf(buf, "Send message to %s (y/n)? ", who);
  687.         message(buf);
  688.         while (((ch = getch()) != 'y') && (ch != 'n'));
  689.         if (ch == 'y') {
  690.             sprintf(buf, "mail %s <%s", who, fn);
  691.             system(buf);
  692.         }
  693.         unlink(fn);
  694.         message("-- Press any key to continue --");
  695.         getch();
  696.  
  697.     } else {
  698.         message("*** Cannot open temp file - press any key to continue ***");
  699.         getch();
  700.     }
  701.  
  702. }
  703.  
  704. /*----------------------- find email address in line --------------------*/
  705.  
  706.  
  707. /*---------------------------------------------------------*/
  708. /* char *get_address()                                     */
  709. /*                                                         */
  710. /* searches for the '@' char in internet addresses and     */
  711. /* then extracts the word the '@' is in.  The terminat-    */
  712. /* ating characters are : ':' '<' '>' '(' ')' '"' '\t'     */
  713. /* '\r' and '\n'; at which point it stops looking.         */
  714. /*                                                         */
  715. /*---------------------------------------------------------*/
  716.  
  717. char *get_address(char *buf, char *addr)
  718. {
  719.     char *p , *c;
  720.     
  721.     /* search for the '@' or "at" that is in every internet address */
  722.     
  723.     if ((p = strchr(buf,'@')) != NULL) {
  724.         c = p;
  725.         while (*p && (*p !=  ' ' && 
  726.                       *p != '\t' && 
  727.                       *p != ':'  && 
  728.                       *p != '<'  && 
  729.                       *p != '\"' && 
  730.                       *p != '('    )) {
  731.             /* quite a few cases to check for */
  732.             p--;
  733.         }
  734.         
  735.         while (*c && (*c !=  ' ' && 
  736.                       *c != '\t' && 
  737.                       *c != ':'  && 
  738.                       *c != '>'  &&
  739.                       *c != '\"' && 
  740.                       *c != '\n' && 
  741.                       *c != '\r' &&
  742.                       *c != ')'    )) {
  743.             /* quite a few cases to check for */
  744.             c++;
  745.         }
  746.         *c = '\0'; 
  747.         strcpy(addr, ++p);
  748.         return addr;
  749.     }
  750.     
  751.     return NULL;
  752. }
  753.  
  754. /*----------------------- get stuff off article header --------------------*/
  755.  
  756. /*---------------------------------------------------------*/
  757. /*  void get_his_stuff()                                   */
  758. /*                                                         */
  759. /*  obtains the address of the person in the passed arti-  */
  760. /*  cle, as well as the msgid.                             */
  761. /*                                                         */
  762. /*---------------------------------------------------------*/
  763.  
  764.  
  765. void get_his_stuff(TEXT *tx, char *author, char *msg_id)
  766. {
  767.     /*
  768.      *  Retrieve the author and msg_id from the article
  769.      */
  770.  
  771.     LINE *ln;
  772.     char *p;
  773.     char buf[256];
  774.     char *null_name = {" < no name > "};
  775.  
  776.     strcpy(author, null_name);
  777.     strcpy(msg_id, " <none> ");
  778.  
  779.     ln = tx->top;
  780.     while (ln != NULL) {
  781.         strcpy(buf, ln->data);
  782.         p = strtok(buf, " :\n\r");
  783.         p = strtok(NULL, " :\n\r");
  784.  
  785.         if (strnicmp(ln->data, "Message-ID:", 11) == 0) {
  786.             p = ln->data + 11;
  787.             while (*p && isspace(*p)) p++;
  788.             p = strtok(p, " :\n\r");
  789.             if (p)
  790.                 strcpy(msg_id, p);
  791.             else
  792.                 strcpy(msg_id, ln->data + 11);
  793.  
  794.         }
  795.  
  796.         if ((strnicmp(ln->data, "From:", 5) == 0) && (strcmp(author, null_name) == 0)) {
  797.             if (get_address(ln->data, author) == NULL) {
  798.                 strcpy(author, p);
  799.             }
  800.         }
  801.  
  802.         if (strnicmp(ln->data, "Reply-To:", 5) == 0) {
  803.             if (get_address(ln->data, author) == NULL) {
  804.                 strcpy(author, p);
  805.             }
  806.         }
  807.  
  808.         if (strlen(ln->data) < 2) break;
  809.         ln = ln->next;
  810.     }
  811. }
  812.  
  813. /*--------------------------- rot 13 the article ------------------------*/
  814. void rot13(TEXT *tx)
  815. {
  816.     LINE *ln;
  817.     int  i, c;
  818.  
  819.  
  820.     ln = tx->start;
  821.  
  822.     while (ln != NULL) {
  823.         for (i = 0; i < strlen(ln->data); i++) {
  824.             c = *((ln->data)+i);
  825.             if ((c >= 'A') && (c <= 'Z')) {
  826.                 *((ln->data)+i) = (((c-'A') + 13) % 26) + 'A';
  827.             } else {
  828.                 if ((c >= 'a') && (c <= 'z')) {
  829.                     *((ln->data)+i) = (((c-'a') + 13) % 26) + 'a';
  830.                 }
  831.             }
  832.         }
  833.         ln = ln->next;
  834.     }
  835. }
  836.  
  837.  
  838. /*--------------------------- expand the tabs ----------------------------*/
  839. void expand_tabs(char *buf, int max_len)
  840. {
  841.     int  l, k;
  842.     char tmp[256], *p, *t;
  843.  
  844.     p = buf;
  845.     t = &tmp[0];
  846.     l = 0;
  847.  
  848.     while ((*p != '\x00') && (l < max_len)) {
  849.         if (*p != '\x09') {
  850.             *t = *p;
  851.             t++;
  852.             p++;
  853.             l++;
  854.         } else {
  855.             p++;
  856.             k = ((l / 8) + 1) * 8;
  857.             for ( ; l < k ; l++) {
  858.                 *t = ' ';
  859.                 t++;
  860.                 if (l >= max_len) break;
  861.             }
  862.         }
  863.     }
  864.  
  865.     *t = '\x00';
  866.     strcpy(buf, tmp);
  867. }
  868.  
  869.